#include "util_ip_helper.h"
#include "exception/Exception.hpp"
#include <arpa/inet.h>
#include <cstring>
#include <fcntl.h>
#include <format>
#include <fstream>
#include <ifaddrs.h>
#include <iostream>
#include <net/if.h>
#include <netinet/in.h>
#include <regex>
#include <sstream>
#include <vector>

namespace util::ip_helper
{

bool IsValidIPv4(const std::string& ip)
{
    try
    {
        const std::regex ipv4Pattern(
            "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}"
            "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");

        return std::regex_match(ip, ipv4Pattern);
    }
    catch (...)
    {
        return false;
    }
}

uint32_t IPToUint(const std::string& ipStr)
{
    struct in_addr addr;
    if (inet_pton(AF_INET, ipStr.c_str(), &addr) != 1)
        return 0;
    return ntohl(addr.s_addr);
}

void GetRoutes(std::vector<SRouteInfo>& routes, std::string& defaultGateway)
{
    std::ifstream routeFile("/proc/net/route");
    if (!routeFile.is_open())
    {
        std::cerr << "Failed to open /proc/net/route" << std::endl;
        return;
    }

    std::string line;
    std::getline(routeFile, line);  // 跳过标题行

    while (std::getline(routeFile, line))
    {
        std::istringstream iss(line);
        std::string        iface, destination, gateway, flags, mask;
        int                refCount, use, metric;

        if (!(iss >> iface >> destination >> gateway >> flags >> refCount >> use >> metric >> mask))
        {
            continue;
        }

        unsigned int      destIp, gateIp, maskIp, flagInt;
        std::stringstream ss;

        ss << std::hex << destination;
        ss >> destIp;
        ss.clear();
        ss << std::hex << gateway;
        ss >> gateIp;
        ss.clear();
        ss << std::hex << mask;
        ss >> maskIp;
        ss.clear();
        ss << std::hex << flags;
        ss >> flagInt;

        struct in_addr addr;
        SRouteInfo     route;
        route.Iface = iface;

        addr.s_addr = destIp;
        route.DstIp = inet_ntoa(addr);

        addr.s_addr  = gateIp;
        route.NextIp = inet_ntoa(addr);

        route.Mask = __builtin_popcount(maskIp);  // GCC/Clang 内置函数，高效计算 1 的个数

        routes.push_back(route);

        if (destIp == 0 && (flagInt & 0x02))
        {
            defaultGateway = route.NextIp;
        }
    }
}

// 判断 IP 是否在指定的网段内
bool is_ip_in_subnet(const std::string& ip, const std::string& subnet)
{  // 192.168.2.1/24
    if (ip == subnet)
    {
        return true;
    }
    size_t pos = subnet.find('/');
    if (pos == std::string::npos) return false;  // 格式不对，返回 false

    std::string network_ip    = subnet.substr(0, pos);
    int         prefix_length = std::stoi(subnet.substr(pos + 1));
    if (ip == network_ip)
    {
        return true;
    }
    uint32_t ip_addr  = IPToUint(ip);
    uint32_t net_addr = IPToUint(network_ip);

    // 计算子网掩码
    uint32_t mask = (prefix_length == 0) ? 0 : ~((1 << (32 - prefix_length)) - 1);

    // 检查 IP 是否在子网范围内
    return (ip_addr & mask) == (net_addr & mask);
}

// 检查 ip 数组中的所有 IP 是否都在 WhiteLists 指定的网段内
bool are_all_ips_in_whitelist(const std::vector<std::string>& ip, const std::vector<std::string>& WhiteLists)
{
    for (const auto& ip_address : ip)
    {
        bool found = false;
        for (const auto& subnet : WhiteLists)
        {
            if (is_ip_in_subnet(ip_address, subnet))
            {
                found = true;
                break;
            }
        }
        if (!found) return false;  // 如果某个 IP 找不到匹配的网段，则返回 false
    }
    return true;
}

// 检查单个 IP 是否在 WhiteLists 指定的网段内
bool is_ip_in_whitelist(const std::string& ip, const std::vector<std::string>& WhiteLists)
{
    for (const auto& subnet : WhiteLists)
    {
        if (is_ip_in_subnet(ip, subnet))
        {
            return true;  // 只要找到一个匹配的网段，就返回 true
        }
    }
    return false;  // 没找到匹配的网段，返回 false
}

std::string GetSegment(const std::string& ip, int mask)
{
    if (mask < 0 || mask > 32)
        throw JHException(std::format("错误的掩码 {}", mask));
    if (mask == 32)
        return ip;
    uint32_t ip_addr = IPToUint(ip);

    uint32_t       mask_ip = 0xFFFFFFFF << (32 - mask);
    uint32_t       net_ip  = ip_addr & mask_ip;
    struct in_addr addr;
    addr.s_addr = htonl(net_ip);

    return inet_ntoa(addr);
}

std::string GetBoardcast(const std::string& ip, int mask)
{
    if (mask < 0 || mask > 32)
        throw JHException(std::format("错误的掩码 {}", mask));
    if (mask == 32)
        return ip;
    uint32_t ip_addr = IPToUint(ip);

    // 计算子网掩码的反码
    uint32_t inverse_mask = ~(0xFFFFFFFF << (32 - mask));
    // 计算网络地址
    uint32_t network_addr = ip_addr & ~inverse_mask;
    // 计算广播地址
    uint32_t       broadcast_addr = network_addr | inverse_mask;
    struct in_addr addr;
    addr.s_addr = htonl(broadcast_addr);
    return inet_ntoa(addr);
}

std::optional<int> GetMaskNum(const std::string& netmaskStr)
{
    struct in_addr addr{};
    if (inet_pton(AF_INET, netmaskStr.c_str(), &addr) != 1)
    {
        return std::nullopt;  // 转换失败，非法地址
    }

    uint32_t mask = ntohl(addr.s_addr);
    if (mask == 0) return std::nullopt;

    int      count = 0;
    uint32_t check = 1 << 31;
    while (mask & check)
    {
        ++count;
        check >>= 1;
    }

    // 检查剩下是否全为 0（确保是连续的 1）
    if ((mask << count) != 0) return std::nullopt;

    return count;
}

std::string FindSegment(const std::string& ipStr, const std::string& netmaskStr, const std::string& skipName)
{
    in_addr ip_addr;
    if (inet_pton(AF_INET, ipStr.c_str(), &ip_addr) != 1)
    {
        return "";  // 非法 IP
    }

    // 获取掩码位数
    std::optional<int> maskBits;
    if (!netmaskStr.empty())
    {
        maskBits = GetMaskNum(netmaskStr);
        if (!maskBits) return "";  // 非法掩码
    }

    // 网络段起点（ip & mask）
    uint32_t ip_net = ntohl(ip_addr.s_addr);
    if (maskBits)
    {
        uint32_t mask = 0xFFFFFFFF << (32 - *maskBits);
        ip_net &= mask;
    }

    // 遍历系统接口
    struct ifaddrs* ifaddr;
    if (getifaddrs(&ifaddr) == -1)
    {
        perror("getifaddrs");
        return "";
    }

    for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
    {
        if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET) continue;
        if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) continue;
        if (skipName == ifa->ifa_name) continue;

        auto*    sa         = (struct sockaddr_in*) ifa->ifa_addr;
        auto*    mask_info  = (struct sockaddr_in*) ifa->ifa_netmask;
        uint32_t local_ip   = ntohl(sa->sin_addr.s_addr);
        uint32_t local_mask = ntohl(mask_info->sin_addr.s_addr);

        auto localBits = GetMaskNum(inet_ntoa(mask_info->sin_addr));
        if (!localBits) continue;

        uint32_t local_net = local_ip & (0xFFFFFFFF << (32 - *localBits));

        // 匹配网段
        if (!maskBits)
        {
            if (local_net == ip_net)
            {
                std::string matchName(ifa->ifa_name);
                freeifaddrs(ifaddr);
                return matchName;
            }
        }
        else
        {
            uint32_t mask = 0xFFFFFFFF << (32 - *maskBits);
            if ((local_ip & mask) == ip_net)
            {
                std::string matchName(ifa->ifa_name);
                freeifaddrs(ifaddr);
                return matchName;
            }
        }
    }

    freeifaddrs(ifaddr);
    return "";  // 没找到
}
}  // namespace util::ip_helper